"""
函数的参数：必传参数、默认参数、不确定参数
"""

#必传参数：在定义函数的时候，没有默认值且必须在函数执行的时候传递进去的参数，且顺序与参数顺序相同
def add(a,b):
    return a+b
result = add(1,2)

#默认参数：在定义函数的时候，通过赋值语句给他一个默认的值
#调用时可以不传默认参数，如果在调用的时候给予了它新的值，函数将优先使用后传入的值
def add(a,b=1):
    return a+b
result = add(1)
result2 = add(1,2)

#不确定参数（可变参数）：没有固定的参数名和数量，不知道要传的参数名具体时什么
def add(*args,**kwargs):
    print(args,type(args))
    print(kwargs,type(kwargs))
add(1,2,3,name='winner',age=20) #1，2，3对应*args  name='winner',age=20对应**kwargs
#*args代表：将无参数名的值合并成元组
#**kwargs代表：将有参数名与默认值的赋值语句合并成字典
#错误传入：
a = (1,2,3,4)
b = {'name':'winner','age':20}
add(a,b)
#返回
#((1, 2, 3, 4), {'name': 'winner', 'age': 20}) <class 'tuple'>
#{} <class 'dict'>
#正确用法
add(*a,**b)
#返回
#(1, 2, 3, 4) <class 'tuple'>
#{'name': 'winner', 'age': 20} <class 'dict'>

#参数规则
#推荐：从左到右依次是必传参数，默认参数，可变元组参数，可变字典参数
def test(a,b=1,*args,**kwargs):
    pass

def test2(a,b=1,*args):
    print(a,b,args)
c = (1,2,3,4)
test2(1,2,*c) #返回1 2 (1, 2, 3, 4)
#test2(a=1,b=2,*c) 报错TypeError: test2() got multiple values for argument 'a'

#如果必传参数、默认参数，可选的元组参数在一起的时候，如果需要赋值传参，需要将可选元组参数放在第一位
def test3(*args,a,b=1):
    print(a,b,args)
test3(a=1,b=2,*c) #返回1 2 (1, 2, 3, 4)

def test4(a,b=1,**kwargs):
    print(a,b,kwargs)
test4(1,2,name='winner',age=20)
test4(a=1,b=2,name='winner',age=20)
test4(name='winner',age=20,a=1,b=2) #name,age不在函数定义的参数名列表中，会封装到字典里
d = {'name':'winner','age':20}
test4(a=1,b=2,**d)#不会报错
test4(**d,a=1,b=2)#不会报错

#参数定义类型的方法：参数名+冒号+类型函数
#函数依然不会对参数类型进行验证
def person(name:str,age:int=20):
    print(name,age)


"""
全局变量与局部变量
"""

#全局变量
#在python脚本最上层代码的变量，全局变量可以在函数内被读取使用，但无法修改
name = 'winner'
def change_name():
    name = 'fangmin'
    print('函数体内：',name) #函数体内： fangmin
change_name()
print('函数外',name) #函数外 winner

#局部变量
#在函数体内定义的变量，局部变量无法在自身函数以外使用
def test():
    new_name = 'fangminx'
    print(new_name)
#无法使用：
#print(new_name)

my_name = 'fangminx'
def test2(a):
    a=10
test2(my_name)
print(my_name) #fangminx

#global将全局变量可以在函数体内进行修改
age = 18
def change_age():
    global age #必须先定义global再使用
    age = 20
change_age()
print(age) #20

#global仅支持字符串、数字、空类型、布尔类型
#如果是列表、字典类型不需要使用global

test_list = ['a','b','c']
def test6():
    test_list.remove('a')
test6()
print(test_list) #['b', 'c']


"""
递归函数
"""
count = 0
def test_count():
    global count
    count += 1
    if count == 10:
        print('count数字变成了10')
    else:
        print(f'count现在的值是：{count}')
        return test_count()
test_count()

"""
匿名函数：lambda
即用即删除，很适合需要完成一项功能，但是此功能只在此一处使用
"""

#无参数的定义
f = lambda: 'f'
print(f())
g = lambda: print('g')
g()

#含参数的定义
f1 = lambda x,y: x+y
print(f1(1,2))
g1 = lambda x,y=1: x+y
print(g1(1))
h1 = lambda x,y=2: x > y
print(h1(3))

#字典排序
users = [
    {"name": "winner"},
    {"name": "fangmin"},
    {"name": "aaaaaaa"},
]
users.sort(key=lambda x:x['name'])
print(users) #[{'name': 'aaaaaaa'}, {'name': 'fangmin'}, {'name': 'winner'}]